From: Keir Fraser Date: Wed, 10 Dec 2008 13:27:14 +0000 (+0000) Subject: Add cpufreq governors: performance, powersave, userspace X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~14026^2~48 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=630b6713472007f100b40bf100246ca169b23a14;p=xen.git Add cpufreq governors: performance, powersave, userspace This patch add 3 more governors beside original running ondemand cpufreq governor. performance governor is with best performance, keeping cpu always running at highest freq; powersave governor is with best power save effect, keeping cpu always running at lowest freq; userspace governor provide user setting freq ability; Signed-off-by: Liu, Jinsong --- diff --git a/xen/drivers/cpufreq/Makefile b/xen/drivers/cpufreq/Makefile index c91c25b715..b87d12777f 100644 --- a/xen/drivers/cpufreq/Makefile +++ b/xen/drivers/cpufreq/Makefile @@ -1,3 +1,4 @@ obj-y += cpufreq.o obj-y += cpufreq_ondemand.o +obj-y += cpufreq_misc_governors.o obj-y += utility.o diff --git a/xen/drivers/cpufreq/cpufreq.c b/xen/drivers/cpufreq/cpufreq.c index 8777a8a822..185b0343d7 100644 --- a/xen/drivers/cpufreq/cpufreq.c +++ b/xen/drivers/cpufreq/cpufreq.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,53 @@ struct cpufreq_dom { }; static LIST_HEAD(cpufreq_dom_list_head); +static LIST_HEAD(cpufreq_governor_list); + +static struct cpufreq_governor *__find_governor(const char *governor) +{ + struct cpufreq_governor *t; + + if (!governor) + return NULL; + + list_for_each_entry(t, &cpufreq_governor_list, governor_list) + if (!strnicmp(governor, t->name, CPUFREQ_NAME_LEN)) + return t; + + return NULL; +} + +int cpufreq_register_governor(struct cpufreq_governor *governor) +{ + if (!governor) + return -EINVAL; + + if (__find_governor(governor->name) != NULL) + return -EEXIST; + + list_add(&governor->governor_list, &cpufreq_governor_list); + return 0; +} + +int cpufreq_unregister_governor(struct cpufreq_governor *governor) +{ + int cpu = smp_processor_id(); + struct cpufreq_policy *policy = cpufreq_cpu_policy[cpu]; + + if (!governor || !policy) + return -EINVAL; + + /* error if unregister current cpufreq governor */ + if (governor == policy->governor) + return -EBUSY; + + if (__find_governor(governor->name) == NULL) + return -ENOENT; + + list_del(&governor->governor_list); + return 0; +} + int cpufreq_limit_change(unsigned int cpu) { struct processor_performance *perf = &processor_pminfo[cpu]->perf; diff --git a/xen/drivers/cpufreq/cpufreq_misc_governors.c b/xen/drivers/cpufreq/cpufreq_misc_governors.c new file mode 100644 index 0000000000..8b391d39f8 --- /dev/null +++ b/xen/drivers/cpufreq/cpufreq_misc_governors.c @@ -0,0 +1,158 @@ +/* + * xen/drivers/cpufreq/cpufreq_misc_gov.c + * + * Copyright (C) 2001 Russell King + * (C) 2002 - 2004 Dominik Brodowski + * + * Nov 2008 Liu Jinsong + * Porting cpufreq_userspace.c, cpufreq_performance.c, and + * cpufreq_powersave.c from Liunx 2.6.23 to Xen hypervisor + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include + + +/* + * cpufreq userspace governor + */ +static int cpufreq_governor_userspace(struct cpufreq_policy *policy, + unsigned int event) +{ + int ret = 0; + + if (!policy) + return -EINVAL; + + switch (event) { + case CPUFREQ_GOV_START: + case CPUFREQ_GOV_STOP: + break; + case CPUFREQ_GOV_LIMITS: + if (policy->max < policy->cur) + ret = __cpufreq_driver_target(policy, policy->max, + CPUFREQ_RELATION_H); + else if (policy->min > policy->cur) + ret = __cpufreq_driver_target(policy, policy->min, + CPUFREQ_RELATION_L); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +struct cpufreq_governor cpufreq_gov_userspace = { + .name = "userspace", + .governor = cpufreq_governor_userspace, +}; + +static int __init cpufreq_gov_userspace_init(void) +{ + return cpufreq_register_governor(&cpufreq_gov_userspace); +} +__initcall(cpufreq_gov_userspace_init); + +static void cpufreq_gov_userspace_exit(void) +{ + cpufreq_unregister_governor(&cpufreq_gov_userspace); +} +__exitcall(cpufreq_gov_userspace_exit); + + +/* + * cpufreq performance governor + */ +static int cpufreq_governor_performance(struct cpufreq_policy *policy, + unsigned int event) +{ + int ret = 0; + + if (!policy) + return -EINVAL; + + switch (event) { + case CPUFREQ_GOV_START: + case CPUFREQ_GOV_STOP: + break; + case CPUFREQ_GOV_LIMITS: + ret = __cpufreq_driver_target(policy, policy->max, + CPUFREQ_RELATION_H); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +struct cpufreq_governor cpufreq_gov_performance = { + .name = "performance", + .governor = cpufreq_governor_performance, +}; + +static int __init cpufreq_gov_performance_init(void) +{ + return cpufreq_register_governor(&cpufreq_gov_performance); +} +__initcall(cpufreq_gov_performance_init); + +static void cpufreq_gov_performance_exit(void) +{ + cpufreq_unregister_governor(&cpufreq_gov_performance); +} +__exitcall(cpufreq_gov_performance_exit); + + +/* + * cpufreq powersave governor + */ +static int cpufreq_governor_powersave(struct cpufreq_policy *policy, + unsigned int event) +{ + int ret = 0; + + if (!policy) + return -EINVAL; + + switch (event) { + case CPUFREQ_GOV_START: + case CPUFREQ_GOV_STOP: + break; + case CPUFREQ_GOV_LIMITS: + ret = __cpufreq_driver_target(policy, policy->min, + CPUFREQ_RELATION_L); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +struct cpufreq_governor cpufreq_gov_powersave = { + .name = "powersave", + .governor = cpufreq_governor_powersave, +}; + +static int __init cpufreq_gov_powersave_init(void) +{ + return cpufreq_register_governor(&cpufreq_gov_powersave); +} +__initcall(cpufreq_gov_powersave_init); + +static void cpufreq_gov_powersave_exit(void) +{ + cpufreq_unregister_governor(&cpufreq_gov_powersave); +} +__exitcall(cpufreq_gov_powersave_exit); diff --git a/xen/drivers/cpufreq/cpufreq_ondemand.c b/xen/drivers/cpufreq/cpufreq_ondemand.c index d860407fca..655edc79e9 100644 --- a/xen/drivers/cpufreq/cpufreq_ondemand.c +++ b/xen/drivers/cpufreq/cpufreq_ondemand.c @@ -263,6 +263,18 @@ struct cpufreq_governor cpufreq_gov_dbs = { .governor = cpufreq_governor_dbs, }; +static int __init cpufreq_gov_dbs_init(void) +{ + return cpufreq_register_governor(&cpufreq_gov_dbs); +} +__initcall(cpufreq_gov_dbs_init); + +static void cpufreq_gov_dbs_exit(void) +{ + cpufreq_unregister_governor(&cpufreq_gov_dbs); +} +__exitcall(cpufreq_gov_dbs_exit); + void __init cpufreq_cmdline_parse(char *str) { do { diff --git a/xen/include/acpi/cpufreq/cpufreq.h b/xen/include/acpi/cpufreq/cpufreq.h index 25b6ce7316..9e3e9477a0 100644 --- a/xen/include/acpi/cpufreq/cpufreq.h +++ b/xen/include/acpi/cpufreq/cpufreq.h @@ -84,9 +84,12 @@ struct cpufreq_governor { char name[CPUFREQ_NAME_LEN]; int (*governor)(struct cpufreq_policy *policy, unsigned int event); + struct list_head governor_list; }; extern struct cpufreq_governor cpufreq_gov_dbs; +extern int cpufreq_register_governor(struct cpufreq_governor *governor); +extern int cpufreq_unregister_governor(struct cpufreq_governor *governor); #define CPUFREQ_DEFAULT_GOVERNOR &cpufreq_gov_dbs /* pass a target to the cpufreq driver */